#ifndef VECTOR3D_H
#define VECTOR3D_H

#include <cmath>

//==============================================================================
class Vector3D {
public:
// ---- Member Variables ----
	
	float x;
	float y;
	float z;



// ---- Constructors ----
	
	Vector3D() {}

	Vector3D(const Vector3D& p_source): x(p_source.x), y(p_source.y), z(p_source.z) {}

	Vector3D(float p_x, float p_y, float p_z): x(p_x), y(p_y), z(p_z) {}



// ---- non vector operation operators ----
	
	// assignment
	Vector3D& operator=(const Vector3D& p_v) {
		x = p_v.x;
		y = p_v.y;
		z = p_v.z;
		return *this;
	} //---------------------------------------



	// equality
	bool operator==(const Vector3D& p_v) const {
		return (x == p_v.x && y == p_v.y && z == p_v.z);
	} //----------------------------------------------

	// inequality
	bool operator!=(const Vector3D& p_v) const {
		return (x != p_v.x || y != p_v.y || z != p_v.z);
	} //-----------------------------------------------



// ---- vector operations ---- 

	// zero a vector
	void zero() {
		x = 0.0f;
		y = 0.0f;
		z = 0.0f;
	} // ---------------------



	// unary - operator for negation
	Vector3D operator-() const {
		return Vector3D(-x, -y, -z);
	} //----------------------------



	// vector addition and subtraction
	Vector3D operator+(const Vector3D& p_v) const {
		return Vector3D(x + p_v.x, y + p_v.y, z + p_v.z);
	} //--------------------------------------------------



	Vector3D operator-(const Vector3D& p_v) const {
		return Vector3D(x - p_v.x, y - p_v.y, z - p_v.z);
	} //------------------------------------------------------



	// multiply and divide
	Vector3D operator*(float p_s) const {
		return Vector3D(x*p_s, y*p_s, z*p_s);
	} //------------------------------------



	Vector3D operator/(float p_s) const {
		float divider = 1.0f / p_s;
		return Vector3D(x*divider, y*divider, z*divider);
	} //-------------------------------------------------



	// combined numeric and assignment operator
	Vector3D& operator+=(const Vector3D& p_v) {
		x += p_v.x;
		y += p_v.y;
		z += p_v.z;
		return *this;
	} //---------------------------------------



	Vector3D& operator-=(const Vector3D& p_v) {
		x -= p_v.x; 
		y -= p_v.y; 
		z -= p_v.z;
		return *this;
	} //-----------------------------------------



	Vector3D& operator*=(const float p_s) {
		x *= p_s;
		y *= p_s;
		z *= p_s;
		return *this;
	} //----------------------------------------



	Vector3D& operator/=(const float p_s) {
		float divider = 1.0f / p_s;
		x *= divider; 
		y *= divider;
		z *= divider;
		return *this;
	} //---------------------------------------



	// normalize
	void normalize() {
		float length = sqrt(x*x + y*y + z*z);
	
		if(length > 0.0f) {
			float divider = 1.0f / length;
			x *= divider;
			y *= divider;
			z *= divider;
		}
	} //-------------------------------------



	float operator*(const Vector3D& p_v) const {
		return x * p_v.x + y * p_v.y + z * p_v.z;
	} //------------------------------------------
}; 
//==============================================================================



inline float vectorMag3D(const Vector3D& p_v) {
	return sqrt(p_v.x * p_v.x + p_v.y * p_v.y + p_v.z * p_v.z);
} //------------------------------------------------------------



inline Vector3D crossProduct(const Vector3D& p_a, const Vector3D& p_b) {
	return Vector3D(	p_a.y*p_b.z - p_a.z*p_b.y,
						p_a.z*p_b.x - p_a.x*p_b.z,
						p_a.x*p_b.y - p_a.y*p_b.x	);
} //----------------------------------------------------------------



// scalar multiplication
inline Vector3D operator*(float p_s, const Vector3D &p_v) {
	return Vector3D(p_s*p_v.x, p_s*p_v.y, p_s*p_v.z);
} //--------------------------------------------------------



// distance between 2 points
inline float distance(const Vector3D& p_a, const Vector3D& p_b) {
	float dx = p_a.x - p_b.x;
	float dy = p_a.y - p_b.y;
	float dz = p_a.z - p_b.z;
	return sqrt(dx*dx + dy*dy + dz*dz);
} //-------------------------------------------------------

#endif